package edu.whu.aspect;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 示例Aspect
 */

@Aspect
@Component
public class DemoAspect {
    Logger logger = LoggerFactory.getLogger(getClass());
    //用来记录方法第几次被调用
    final Map<String,TimeRecorder> times= Collections.synchronizedMap(new HashMap<>());

    @Pointcut("execution(* edu.whu.service.*.*(..))")
    public void servicePointCut(){ }

    @Before("servicePointCut()")
    public void beforePointCut(JoinPoint jp){
        String info= "before:进入"+jp.getSignature()+"方法,";
        info +="参数是：";
        for (Object arg : jp.getArgs()) {
            info+= arg+" ";
        }
        if(!times.containsKey(jp.getSignature())){
            times.put(jp.getSignature().getName(),new TimeRecorder());
        }else{
            times.get(jp.getSignature().getName()).invokeTimes+=1;
        }
        logger.info(info);
    }

    @After("servicePointCut()")
    public void afterPointCut(JoinPoint jp) {
        logger.info("after:退出方法...");
    }

    @Around("servicePointCut()")
    public Object aroundPointcut(ProceedingJoinPoint joinPoint) throws Throwable {
        long t1= Calendar.getInstance().getTimeInMillis();
        logger.info("around:进入"+joinPoint.getSignature()+"方法...");
        Object retVal = joinPoint.proceed();
        long t2= Calendar.getInstance().getTimeInMillis();
        logger.info("around:退出"+joinPoint.getSignature()+"方法,耗时："+(t2-t1));
        if((t2-t1)>times.get(joinPoint.getSignature().getName()).longestTime){
            times.get(joinPoint.getSignature().getName()).longestTime=(t2-t1);
        }
        if((t2-t1)<times.get(joinPoint.getSignature().getName()).shortestTime){
            times.get(joinPoint.getSignature().getName()).shortestTime=(t2-t1);
        }
        times.get(joinPoint.getSignature().getName()).averageTime=((t2-t1)+
                times.get(joinPoint.getSignature().getName()).averageTime*
                        times.get(joinPoint.getSignature().getName()).invokeTimes-1)/
                times.get(joinPoint.getSignature().getName()).invokeTimes;
        logger.info( times.get(joinPoint.getSignature().getName()).toString());
        return retVal;
    }

    @AfterReturning(pointcut = "servicePointCut()", returning = "ret")
    public Object afterPointCutReturn(JoinPoint jp,Object ret) {
        logger.info("afterReturning:返回值为："+ret);
        return ret;
    }


    @AfterThrowing(pointcut= "servicePointCut()",throwing="ex")
    public void afterPointCutThrow(JoinPoint jp,Exception ex) {
        times.get(jp.getSignature().getName()).exceptionTimes+=1;
        logger.error("afterThrowing:异常为："+ex);
    }

}
